<?php

namespace addons\third\library;

use fast\Http;
use think\Config;
use think\Exception;
use think\Log;

//use EasyWeChat\Foundation\Application as WeApplication;
//use EasyWeChat\MiniProgram\Encryption\Encryptor;

/**
 * 微信小程序
 */
class Wemini
{

    public $openid;
    public $unionId;
    const GET_AUTH_CODE_URL = '';
    const GET_OPENID_URL = 'https://api.weixin.qq.com/sns/jscode2session';

    /**
     * 配置信息
     * @var array
     */
    private $config = [];

    public function __construct($options = [])
    {
        if ($config = Config::get('third.wemini')) {
            $this->config = array_merge($this->config, $config);
        }
        $this->config = array_merge($this->config, is_array($options) ? $options : []);
    }

    public function getOpenId($code)
    {
        if($code){
            $data = [];
            $data['appid'] = $this->config['app_id'];
            $data['secret'] = $this->config['app_secret'];
            $data['js_code'] = $code;
            $data['grant_type'] = 'authorization_code';
            $url = self::GET_OPENID_URL . '?' . http_build_query($data);
            $ret = Http::get($url);
            $result = json_decode($ret, true);
            if (!$result || isset($result['errcode'])) {
                Log::record($ret, Log::ERROR);
                throw new Exception($result['errmsg'], 3);
            }
            if(!isset($result['unionid'])){
                throw new Exception("未绑定微信开放平台，请于管理员联系", 4);
            }
            $old_session = session('wemini_session_key');
            if($old_session){
                session('old_wemini_session_key', $old_session);
            }
            session('wemini_session_key', $result);
        }else{
            $result = session('wemini_session_key');
        }

        return $result;
    }


    /**
     * 获取用户信息
     * @param array $params
     * @return array
     */
    public function getUserInfo($params = [])
    {
        $params = $params ? $params : $_GET;
        list($code, $rawData, $signature, $encryptedData, $iv) = array_values($params);
        
        if (empty($rawData) || empty($signature) || empty($encryptedData) || empty($iv)) {
            return [];
        }

        // $app = new \EasyWeChat\Foundation\Application([
        //     'mini_program'=>[
        //         'app_id'    => $this->config['app_id'],
        //         'secret'    => $this->config['app_secret'],
        //     ]
        // ]);
//        $info = $app->mini_program->sns->getSessionKey($code);

        $app = \EasyWeChat\Factory::miniProgram([
            'app_id'    => $this->config['app_id'],
            'secret'    => $this->config['app_secret'],
        ]);
        if($code){
            $session_key = $app->auth->session($code);
            if (!$session_key || isset($result['errcode'])) {
                Log::record($session_key, Log::ERROR);
                throw new Exception($session_key['errmsg'], 3);
            }
            if(!isset($result['unionid'])){
                throw new Exception("未绑定微信开放平台，请于管理员联系", 4);
            }
            $old_session = session('wemini_session_key');
            if($old_session){
                session('old_wemini_session_key', $old_session);
            }
            session('wemini_session_key', $session_key);
        }
        $session_key = session('wemini_session_key');
        //\think\Log::record("getSessionKey########");
        //\think\Log::record($session_key);
        if(empty($session_key)){
            throw new Exception('授权已过期，请重新授权！', 60000);
        }
        $this->openid = $session_key['openid'];
        $this->unionId = isset($session_key['unionid']) ? $session_key['unionid'] : '';
        $session_key = $session_key['session_key'];
        
        // 数字签名校验 
        $signature2 = sha1(htmlspecialchars_decode(stripslashes($rawData)) . $session_key);
        if ($signature != $signature2) {
            throw new Exception('签名错误！', 60000);
        }
        // 获取信息，对接口进行解密
        $data = $app->encryptor->decryptData($session_key, $iv, $encryptedData);
        $data['openid'] = $this->openid;
        $data['openId'] = $this->openid;
//        $data['openid'] = $data['openId'];
        $data['unionid'] = $this->unionId;
        $access_token = $app->auth->getAccessToken($app)->getToken();
        $data['access_token'] = $access_token['access_token'];
        $data['expires_in'] = $access_token['expires_in'];
        $data['refresh_token'] = '';
        if (isset($data['gender'])) {
            if ($data['gender'] == 2) {
                $data['gender'] = 0;
            } else if ($data['gender'] == 0) {
                $data['gender'] = 2;
            }
        } else {
            $data['gender'] = 1;
        }
        $data['userinfo'] = [
            'language'  => $data['language'],
            'nickname'  => $data['nickName'],
            'avatar'    => $data['avatarUrl'],
            'gender'    => $data['gender'],
        ];
//        // 获取信息，对接口进行解密
//        $Encryptor = new Encryptor($this->config['app_id'], '', '');
//        $data = $Encryptor->decryptData($session_key, $iv, $encryptedData);

        session('wemini_user_info', $data);
        return $data;
    }

    /**
     * 新解密手机号
     * @param array $params
     * @return void
     */
    public function getPhoneNumber($params = [])
    {
        $params = $params ? $params : $_GET;
        list($code) = array_values($params);
        if (empty($code)) {
            throw new Exception('参数错误！');
        }
//        // 获取信息，获取手机号码
        $app = \EasyWeChat\Factory::miniProgram([
            'app_id' => $this->config['app_id'],
            'secret' => $this->config['app_secret'],
        ]);
        $data = $app->user->getPhoneNumber($code);
        //\think\Log::record("getPhoneNumber########");
        //\think\Log::record($data);
//        return ['countryCode' => $data['countryCode'], 'purePhoneNumber' => $data['purePhoneNumber'], 'openid' => $result['openid']];
        return $data;
    }

    /**
     * 解密手机号
     *
     * @param array $params
     * @return void
     */
    public function decryptorMobile($params = [])
    {
        $params = $params ? $params : $_GET;
        list($encryptedData, $iv) = array_values($params);
        if (empty($encryptedData) || empty($iv)) {
            throw new Exception('参数错误！');
        }
//        $result = $this->getOpenId($params['code']);
        $result = session('wemini_session_key');
        // \think\Log::record("getOpenId########");
        // \think\Log::record($result);
        $this->openid = $result['openid'];
        $session_key = $result['session_key'];
//        // 获取信息，对接口进行解密
//        $app = \EasyWeChat\Factory::miniProgram([
//            'app_id' => $this->config['app_id'],
//            'secret' => $this->config['app_secret'],
//        ]);
//        $data = $app->encryptor->decryptData($session_key, $iv, $encryptedData);
        $data = $this->decryptData($session_key, $iv, $encryptedData);
        //\think\Log::record("decryptData########");
        //\think\Log::record($data);
//        return ['countryCode' => $data['countryCode'], 'purePhoneNumber' => $data['purePhoneNumber'], 'openid' => $result['openid']];
        return $data;
    }

    /**
     * 微信解密
     * @param $encryptedData
     * @param $iv
     * @param $data
     */
    public function decryptData($session_key , $iv, $encryptedData){
        if (!in_array(strlen($session_key), [16, 24, 32], true)) {
//            throw new Exception(sprintf('Key length must be 16, 24, or 32 bytes; got key len (%s).', strlen($session_key)));
            throw new Exception("sessionKey非法");
        }

        $aesKey=base64_decode($session_key);

        if (strlen($iv) != 24) {
            throw new Exception('IV length must be 24 bytes.');
        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);

        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, OPENSSL_RAW_DATA , $aesIV);
        $dataObj = json_decode( $result );
        if( $dataObj  == NULL )
        {
            throw new Exception(' aes 解密失败', 60000);
        }
        if( $dataObj->watermark->appid != $this->config['app_id'] )
        {
            throw new Exception(' aes 解密失败app_id', 60000);
        }
        return $dataObj;
    }

}
